package com.cskaoyan.javase.object._6clone;

/**
 * clone方法
 * clone方法的方法声明为：
 * protected native Object clone() throws CloneNotSupportedException;
 * 注意:
 *      1.这是一个protected访问权限的方法,所以使用该方法,首先要注意访问权限问题
 *      2.这是一个本地方法不需要方法体
 *      3.该方法的返回值类型是Object,就是返回一个对象
 *      4.throws CloneNotSupportedException 是方法抛出异常的声明,先不管它
 *
 * 方法的作用:
 *      某个对象通过调用clone方法,来创建一个和自身对象完全一模一样的对象
 *      这就是Object类当中的clone方法的默认实现
 *      注意克隆后的对象,要求和原先的对象是独立的新对象
 *      而且属性的取值应该是完全一样的,行为也是一致的
 *
 * clone方法的使用流程:
 *      1.(必做的)在默认情况下,只能在一个类当中去调用自身clone方法,就是只能克隆自己
 *          大多数情况下是没有意义的
 *          所以使用clone方法第一步就需要突破访问权限的限制
 *          于是就需要重写方法,重写访问权限.
 *
 *      2.(非必要,但是建议)clone方法的默认实现是获取一个和原先对象完全一样的新对象,是不会改变对象的类型的
 *      所以该方法的返回值类型,也可以重写
 *      建议在类中重写clone方法时,顺手重写返回值类型,这样使用clone方法会更加方便.
 *
 *      3.(必须的)
 *      如果想要某个类的对象做克隆操作,那么该类就必须实现接口java.lang.Cloneable
 *      否者强行克隆该类对象,会抛出异常CloneNotSupportedException
 *
 * 注意事项:
 *      1.Object类当中本地方法,clone会得到一个,和原先对象完全一样的独立的新对象
 *          这种创建对象的方式,不同于new对象,不会执行构造器
 *          和new对象是一种平行的创建对象的方式,是一种新的创建对象的方式.
 *
 *          实际开发中,这种创建对象的方式很少见,假如有以下需求:
 *              得到一个新的完全独立的,但是和之前对象一样的新对象
 *          可以考虑使用clone,但实际很少见.
 *
 *     2.java.lang.Cloneable接口是一个空接口
 *          那么空接口的作用是什么呢?
 *          是一个标记接口
 *          实现这种标记接口就允许做克隆操作
 *
 *     3.浅克隆以及深克隆
 *     浅克隆指的是: 对象当中的基本数据类型属性,可以一份独立的成员变量;
 *     但是对象中的引用数据类型,克隆的是引用
 *     克隆后的引用和原先的引用仍然指向同一个对象
 *     那么这时原先的对象和克隆对象,不是完全独立的
 *     这就是浅克隆
 *
 *
 * @since 16:24
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Student s1 = new Student(18, 700);
        // 'clone()' has protected access in 'java.lang.Object'
        // s1.clone();
        // Student类重写方法后,就可以调用该方法了
        Student cloneStu = s1.clone();
        System.out.println(s1 == cloneStu);
        System.out.println(s1.equals(cloneStu));
    }
}

/*
interface Cloneable {
}
*/
interface MyCloneable extends Cloneable {

}

class Student implements MyCloneable {
    int age;
    double score;

/*    public void test() throws CloneNotSupportedException {
        this.clone();
    }*/

    public Student(int age, double score) {
        System.out.println("构造器执行了!");
        this.age = age;
        this.score = score;
    }

    @Override
    protected Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return Double.compare(student.score, score) == 0;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = age;
        temp = Double.doubleToLongBits(score);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}